#!/bin/bash

# Web服务器配置自动化模块
# 支持Nginx用户自动检测、SSL证书生成、虚拟主机配置等功能

# =============================================================================
# Web服务器配置函数库
# =============================================================================

# 检测和修复Nginx用户配置
fix_nginx_user_config() {
    local web_user=$(detect_web_user)
    
    if command -v print_message >/dev/null 2>&1; then
        print_message "$YELLOW" "检测和修复Nginx用户配置..."
    else
        echo "检测和修复Nginx用户配置..."
    fi
    
    # 检查当前Nginx配置中的用户设置
    if [[ -f /etc/nginx/nginx.conf ]]; then
        local current_user=$(grep -E "^user\s+" /etc/nginx/nginx.conf | awk '{print $2}' | sed 's/;//')
        
        if [[ "$current_user" != "$web_user" ]]; then
            if command -v print_message >/dev/null 2>&1; then
                print_message "$YELLOW" "检测到Nginx用户配置不匹配: $current_user -> $web_user"
            else
                echo "检测到Nginx用户配置不匹配: $current_user -> $web_user"
            fi
            
            # 备份原配置
            cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup.$(date +%Y%m%d-%H%M%S)
            
            # 修复用户配置
            sed -i "s/^user\s\+[^;]\+;/user $web_user;/" /etc/nginx/nginx.conf
            
            if command -v print_message >/dev/null 2>&1; then
                print_message "$GREEN" "✓ Nginx用户配置已修复: $web_user"
            else
                echo "✓ Nginx用户配置已修复: $web_user"
            fi
        else
            if command -v print_message >/dev/null 2>&1; then
                print_message "$GREEN" "✓ Nginx用户配置正确: $web_user"
            else
                echo "✓ Nginx用户配置正确: $web_user"
            fi
        fi
    fi
    
    # 确保Web用户存在
    if ! id "$web_user" &>/dev/null; then
        echo "创建Web用户: $web_user"
        useradd -r -s /bin/false "$web_user" 2>/dev/null || true
    fi
    
    return 0
}

# 生成SSL自签名证书
generate_ssl_certificate() {
    local domain="${1:-localhost}"
    local cert_dir="/etc/nginx/ssl"
    local cert_file="$cert_dir/$domain.crt"
    local key_file="$cert_dir/$domain.key"
    
    echo "为域名 $domain 生成SSL证书..."
    
    # 创建SSL目录
    mkdir -p "$cert_dir"
    
    # 检查是否已存在证书
    if [[ -f "$cert_file" && -f "$key_file" ]]; then
        # 检查证书是否即将过期（30天内）
        if openssl x509 -checkend 2592000 -noout -in "$cert_file" 2>/dev/null; then
            echo "✓ SSL证书已存在且有效: $domain"
            return 0
        else
            echo "SSL证书即将过期，重新生成..."
        fi
    fi
    
    # 生成私钥
    if ! openssl genrsa -out "$key_file" 2048 2>/dev/null; then
        echo "⚠ 无法生成SSL私钥，跳过HTTPS配置"
        return 1
    fi
    
    # 生成证书签名请求配置
    local csr_config="/tmp/ssl_csr_$domain.conf"
    cat > "$csr_config" << EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = v3_req

[dn]
C=CN
ST=Beijing
L=Beijing
O=Personal Cloud Notes
OU=IT Department
CN=$domain

[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = $domain
DNS.2 = localhost
DNS.3 = *.localhost
IP.1 = 127.0.0.1
IP.2 = ::1
EOF
    
    # 生成自签名证书
    if openssl req -new -x509 -key "$key_file" -out "$cert_file" -days 365 -config "$csr_config" -extensions v3_req 2>/dev/null; then
        # 设置权限
        chmod 600 "$key_file"
        chmod 644 "$cert_file"
        chown root:root "$key_file" "$cert_file"
        
        # 清理临时文件
        rm -f "$csr_config"
        
        echo "✓ SSL证书生成成功: $domain"
        echo "证书文件: $cert_file"
        echo "私钥文件: $key_file"
        return 0
    else
        echo "⚠ SSL证书生成失败，将使用HTTP配置"
        rm -f "$csr_config" "$key_file" "$cert_file"
        return 1
    fi
}

# 生成虚拟主机配置
generate_virtual_host_config() {
    local domain="${1:-localhost}"
    local enable_ssl="${2:-true}"
    local deploy_path="${3:-/opt/personal-cloud-notes}"
    local app_port="${4:-3000}"
    local config_file="/etc/nginx/sites-available/personal-cloud-notes-$domain"
    
    echo "生成虚拟主机配置: $domain"
    
    # 检查SSL证书是否可用
    local ssl_available=false
    if [[ "$enable_ssl" == "true" ]]; then
        if generate_ssl_certificate "$domain"; then
            ssl_available=true
        fi
    fi
    
    # 生成配置文件
    cat > "$config_file" << EOF
# 个人云笔记虚拟主机配置
# 域名: $domain
# 生成时间: $(date)
# SSL启用: $ssl_available

EOF
    
    # 如果启用SSL，添加HTTP到HTTPS重定向
    if [[ "$ssl_available" == "true" ]]; then
        cat >> "$config_file" << EOF
# HTTP重定向到HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name $domain;
    
    # 重定向到HTTPS
    return 301 https://\$server_name\$request_uri;
}

# HTTPS主配置
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name $domain;
    
    # SSL配置
    ssl_certificate /etc/nginx/ssl/$domain.crt;
    ssl_certificate_key /etc/nginx/ssl/$domain.key;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    
    # 现代SSL配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    
    # HSTS
    add_header Strict-Transport-Security "max-age=63072000" always;
    
EOF
    else
        # HTTP配置
        cat >> "$config_file" << EOF
# HTTP配置
server {
    listen 80;
    listen [::]:80;
    server_name $domain;
    
EOF
    fi
    
    # 添加通用配置
    cat >> "$config_file" << EOF
    root $deploy_path/public;
    index index.html index.htm;
    
    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
    
    # 日志配置
    access_log /var/log/nginx/$domain.access.log;
    error_log /var/log/nginx/$domain.error.log;
    
    # API代理配置
    location /api/ {
        proxy_pass http://127.0.0.1:$app_port;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        proxy_cache_bypass \$http_upgrade;
        
        # 超时设置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        
        # 缓冲设置
        proxy_buffering on;
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
        
        # 速率限制
        limit_req zone=api burst=20 nodelay;
        limit_conn conn_limit_per_ip 10;
    }
    
    # WebSocket支持
    location /socket.io/ {
        proxy_pass http://127.0.0.1:$app_port;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }
    
    # 文件上传处理
    location /api/upload {
        proxy_pass http://127.0.0.1:$app_port;
        proxy_http_version 1.1;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        
        # 上传文件大小限制
        client_max_body_size 100M;
        client_body_buffer_size 128k;
        client_body_timeout 120s;
        
        # 禁用缓冲以支持大文件上传
        proxy_request_buffering off;
        proxy_buffering off;
        
        # 速率限制
        limit_req zone=upload burst=5 nodelay;
    }
    
    # 静态资源优化
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|webp|avif)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Vary "Accept-Encoding";
        
        # 启用gzip压缩
        gzip_static on;
        
        # 跨域设置（如果需要）
        # add_header Access-Control-Allow-Origin "*";
    }
    
    # 用户文件访问控制
    location /data/users/ {
        internal;
        alias $deploy_path/data/users/;
    }
    
    # 受保护的文件下载
    location /api/files/download/ {
        proxy_pass http://127.0.0.1:$app_port;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }
    
    # SPA路由支持
    location / {
        try_files \$uri \$uri/ /index.html;
        
        # 缓存HTML文件
        location ~* \.html$ {
            expires 1h;
            add_header Cache-Control "public, must-revalidate";
        }
    }
    
    # 健康检查端点
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }
    
    # 安全设置
    location ~ /\.(ht|git|svn) {
        deny all;
    }
    
    location ~ /(config|scripts|database)/ {
        deny all;
    }
    
    # 限制访问敏感文件
    location ~* \.(env|log|sql|bak|backup)$ {
        deny all;
    }
}
EOF
    
    echo "✓ 虚拟主机配置生成完成: $domain"
    return 0
}

# 生成Nginx主配置
generate_nginx_main_config() {
    local web_user=$(detect_web_user)
    
    echo "生成Nginx主配置..."
    
    # 备份原配置
    if [[ -f /etc/nginx/nginx.conf ]]; then
        cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup.$(date +%Y%m%d-%H%M%S)
    fi
    
    # 生成优化的主配置文件
    cat > /etc/nginx/nginx.conf << EOF
# 个人云笔记 Nginx 主配置文件
# 自动生成于: $(date)
# 优化配置，支持高并发和大文件上传

user $web_user;
worker_processes auto;
worker_rlimit_nofile 65535;
pid /var/run/nginx.pid;

# 错误日志
error_log /var/log/nginx/error.log warn;

events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
    accept_mutex off;
}

http {
    # 基础设置
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    # 字符集
    charset utf-8;
    
    # 日志格式
    log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" '
                    '\$status \$body_bytes_sent "\$http_referer" '
                    '"\$http_user_agent" "\$http_x_forwarded_for" '
                    '\$request_time \$upstream_response_time';
    
    log_format json escape=json '{'
        '"time_local":"\$time_local",'
        '"remote_addr":"\$remote_addr",'
        '"remote_user":"\$remote_user",'
        '"request":"\$request",'
        '"status": "\$status",'
        '"body_bytes_sent":"\$body_bytes_sent",'
        '"request_time":"\$request_time",'
        '"http_referrer":"\$http_referer",'
        '"http_user_agent":"\$http_user_agent"'
    '}';
    
    access_log /var/log/nginx/access.log main;
    
    # 性能优化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    keepalive_requests 1000;
    types_hash_max_size 2048;
    server_tokens off;
    
    # 客户端设置
    client_max_body_size 100M;
    client_body_buffer_size 128k;
    client_header_buffer_size 32k;
    large_client_header_buffers 4 32k;
    client_body_timeout 60s;
    client_header_timeout 60s;
    send_timeout 60s;
    
    # 连接池优化
    upstream_keepalive_connections 32;
    upstream_keepalive_requests 1000;
    upstream_keepalive_timeout 60s;
    
    # Gzip压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml+rss
        application/atom+xml
        image/svg+xml;
    
    # 缓存设置
    open_file_cache max=10000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
    
    # 速率限制
    limit_req_zone \$binary_remote_addr zone=api:10m rate=10r/s;
    limit_req_zone \$binary_remote_addr zone=upload:10m rate=2r/s;
    limit_conn_zone \$binary_remote_addr zone=conn_limit_per_ip:10m;
    
    # 包含其他配置文件
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}
EOF
    
    echo "✓ Nginx主配置生成完成"
    return 0
}

# 配置Nginx Web服务器
configure_nginx_server() {
    local domain="${1:-localhost}"
    local enable_ssl="${2:-true}"
    local deploy_path="${3:-/opt/personal-cloud-notes}"
    local app_port="${4:-3000}"
    
    echo "配置Nginx Web服务器..."
    
    # 创建必要的目录
    mkdir -p /etc/nginx/sites-available
    mkdir -p /etc/nginx/sites-enabled
    mkdir -p /etc/nginx/conf.d
    mkdir -p /etc/nginx/ssl
    mkdir -p /var/log/nginx
    
    # 修复Nginx用户配置
    fix_nginx_user_config || return 1
    
    # 生成主配置
    generate_nginx_main_config || return 1
    
    # 生成虚拟主机配置
    generate_virtual_host_config "$domain" "$enable_ssl" "$deploy_path" "$app_port" || return 1
    
    # 启用站点
    local config_name="personal-cloud-notes-$domain"
    if [[ ! -L "/etc/nginx/sites-enabled/$config_name" ]]; then
        ln -s "/etc/nginx/sites-available/$config_name" "/etc/nginx/sites-enabled/"
    fi
    
    # 禁用默认站点
    if [[ -L /etc/nginx/sites-enabled/default ]]; then
        rm -f /etc/nginx/sites-enabled/default
    fi
    
    # 验证配置
    if nginx -t; then
        echo "✓ Nginx配置验证成功"
        
        # 重新加载配置
        if systemctl is-active nginx >/dev/null 2>&1; then
            if systemctl reload nginx; then
                echo "✓ Nginx配置重新加载成功"
            else
                echo "⚠ Nginx配置重新加载失败，尝试重启..."
                systemctl restart nginx
            fi
        else
            systemctl start nginx
        fi
        
        return 0
    else
        echo "❌ Nginx配置验证失败"
        return 1
    fi
}

# 验证Web服务器配置
verify_nginx_config() {
    local domain="${1:-localhost}"
    local app_port="${2:-3000}"
    
    echo "验证Web服务器配置..."
    
    local errors=()
    
    # 检查Nginx服务状态
    if systemctl is-active nginx >/dev/null 2>&1; then
        echo "✓ Nginx服务运行正常"
    else
        errors+=("Nginx服务未运行")
    fi
    
    # 检查端口监听
    if netstat -tlnp 2>/dev/null | grep -q ":80 "; then
        echo "✓ HTTP端口 80 监听正常"
    else
        errors+=("HTTP端口 80 未监听")
    fi
    
    if netstat -tlnp 2>/dev/null | grep -q ":443 "; then
        echo "✓ HTTPS端口 443 监听正常"
    else
        echo "⚠ HTTPS端口 443 未监听（可能未启用SSL）"
    fi
    
    # 检查配置文件语法
    if nginx -t >/dev/null 2>&1; then
        echo "✓ Nginx配置语法正确"
    else
        errors+=("Nginx配置语法错误")
    fi
    
    # 检查SSL证书（如果存在）
    if [[ -f "/etc/nginx/ssl/$domain.crt" ]]; then
        if openssl x509 -checkend 86400 -noout -in "/etc/nginx/ssl/$domain.crt" 2>/dev/null; then
            echo "✓ SSL证书有效"
        else
            errors+=("SSL证书无效或即将过期")
        fi
    fi
    
    # 输出结果
    if [[ ${#errors[@]} -gt 0 ]]; then
        echo "Web服务器配置验证失败:"
        printf '%s\n' "${errors[@]}"
        return 1
    else
        echo "✓ Web服务器配置验证通过"
        return 0
    fi
}

# 导出函数供其他脚本使用
export -f fix_nginx_user_config
export -f generate_ssl_certificate
export -f generate_virtual_host_config
export -f generate_nginx_main_config
export -f configure_nginx_server
export -f verify_nginx_config